package cs304.p3.library.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import cs304.p3.library.model.DBTableModel.TableType;

public class MainController extends Controller {
	
	public static enum CommandType{ HELP, CLEAR, TYPES, SWITCH, SETURL, INSERT, UPDATE, DELETE, INSERTVIEW, UPDATEVIEW, DELETEVIEW, DISPLAY, EXIT, INVALID};
	
	private static final String INVALID_ARGS_MSG = "\nInvalid or missing arguments! Type ? or help to see a list of commands.";
	private static final String INVALID_CMD_MSG = "\nInvalid command! Type ? or help to see a list of commands.";
	private static final String INVALID_TYPE_MSG = "\nInvalid type for insert command! Type \"types\" for a list of types";
	private static final String SWITCH_MSG = "\nSwitching user...";
	private static final String SETURL_MSG = "\nSetting url...";
	private static final String DISPLAY_MSG = "\nDisplay set";
	private static final String INSERT_VIEW_MSG = "Starting Insert View";
	private static final String UPDATE_VIEW_MSG = "Starting Update View";
	private static final String DELETE_VIEW_MSG = "Starting Delete View";
	private static final String TYPES_LIST =
			"\nTypes:\n" +
			"borrower\n" +
			"borrower_type\n" +
			"book\n" +
			"hassubject\n" +
			"hasauthor\n" +
			"holdrequest\n" +
			"bookcopy\n" +
			"borrowing\n" +
			"fine\n";
	private static final String HELP_MSG = 
			"\nAvaliable Commands:\n" +
			"?/help - See a list of commands\n" +
			"clear - Clears the command history\n" +
			"types/type/t - Display types that can be inserted, updated, deleted and displayed\n" +
			"switch [name] [password] - Switch user to UBC's Database\n" +
			"seturl [URL] - Sets the connection url for UBC's Database\n" +
			"insert [type] [args...] - Insert [type] with [args...] into Database\n" +
			"insertview / iv [type] - Launches the Insert GUI View for [type]\n" +
			"update [type] [args...] [new_args...] - Update [type] with [args...] set to [new_args...] in Database\n" +
			"updateview / uv [type] - Launches the Update GUI View for [type]\n" +
			"delete [type] [args...] - Delete [type] with [args...] in Database\n" +
			"deleteview / dv [type] - Launches the Delete GUI View for [type]\n" +
			"display [type] - display table idetified by [type]\n" +
			"exit/quit/q - Logout and exit the application\n";
	
	//private MainFrame frame;
	
	public Command parseCmd(String cmd) {
		StringTokenizer tokens = new StringTokenizer(cmd);
		
		if(tokens.countTokens() < 1) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
		String cmdtype = tokens.nextToken();
		
		if(cmdtype.equals("switch")){
			if(tokens.countTokens() < 2) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			return new Command(CommandType.SWITCH, SWITCH_MSG, tokens.nextToken(), tokens.nextToken());
		}else if(cmdtype.equals("seturl")){
			
			if(tokens.countTokens() < 1) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			return new Command(CommandType.SETURL, SETURL_MSG, tokens.nextToken());
			
		}else if(cmdtype.equals("insert")){
			
			if(tokens.countTokens() < 1) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			String dbType = tokens.nextToken();
			List<String> args = new ArrayList<String>();
			TableType tableType = parseTableType(dbType);
			if(tableType == null) return new Command(CommandType.INVALID, INVALID_TYPE_MSG);
			if(tokens.countTokens() != tableType.getCount()) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			while(tokens.hasMoreTokens()) args.add(tokens.nextToken());
			return new Command(CommandType.INSERT, dbType, tableType, args.toArray(new String[0]));
			
		}else if(cmdtype.equals("update")){
			
			if(tokens.countTokens() < 1) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			return new Command(CommandType.UPDATE, "Starting Update Dialog...", tokens.nextToken());
			
		}else if(cmdtype.equals("delete")){
			
			if(tokens.countTokens() < 2) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			String dbType = tokens.nextToken();
			List<String> args = new ArrayList<String>();
			TableType tableType = parseTableType(dbType);
			if(tableType == null) return new Command(CommandType.INVALID, INVALID_TYPE_MSG);
			if(tokens.countTokens() != tableType.getCount()) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			while(tokens.hasMoreTokens()) args.add(tokens.nextToken());
			return new Command(CommandType.DELETE, dbType, tableType, args.toArray(new String[0]));
			
			/*if(dbType.equals("bookcopy")){
				if(tokens.countTokens() < 2) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
				return new Command(CommandType.DELETE, "bookcopy", tokens.nextToken(), tokens.nextToken());
			}else return new Command(CommandType.DELETE, dbType, tokens.nextToken());*/
			
		}else if(cmdtype.equals("insertview") || cmdtype.equals("iv")){
			
			if(tokens.countTokens() < 1) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			return new Command(CommandType.INSERTVIEW, INSERT_VIEW_MSG, tokens.nextToken());
			
		}else if(cmdtype.equals("updateview") || cmdtype.equals("uv")){
			
			if(tokens.countTokens() < 1) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			return new Command(CommandType.UPDATEVIEW, UPDATE_VIEW_MSG, tokens.nextToken());
			
		}else if(cmdtype.equals("deleteview") || cmdtype.equals("dv")){
			
			if(tokens.countTokens() < 1) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			return new Command(CommandType.DELETEVIEW, DELETE_VIEW_MSG, tokens.nextToken());
			
		}else if(cmdtype.equals("display")){
			
			if(tokens.countTokens() < 1) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			String dbType = tokens.nextToken();
			TableType tableType = parseTableType(dbType);
			if(tableType == null) return new Command(CommandType.INVALID, INVALID_ARGS_MSG);
			return new Command(CommandType.DISPLAY, DISPLAY_MSG, tableType);
			
		}else if(cmdtype.equals("types") || cmdtype.equals("type") || cmdtype.equals("t")){
			return new Command(CommandType.TYPES, TYPES_LIST);
		}else if(cmdtype.equals("clear")){
			return new Command(CommandType.CLEAR, "");
		}else if(cmdtype.equals("?") || cmdtype.equals("help")){
			return new Command(CommandType.HELP, HELP_MSG);
		}else if(cmdtype.equals("quit") || cmdtype.equals("exit") || cmdtype.equals("q")){
			return new Command(CommandType.EXIT, "");
		}else{
			return new Command(CommandType.INVALID, INVALID_CMD_MSG);
		}
	}
	
	private static final TableType parseTableType(String dbType){
		if(dbType.equals("borrower")){
			return TableType.BORROWER;
		}else if(dbType.equals("borrower_type")){
			return TableType.BORROWERTYPE;
		}else if(dbType.equals("book")){
			return TableType.BOOK;
		}else if(dbType.equals("hasauthor")){
			return TableType.HASAUTHOR;
		}else if(dbType.equals("hassubject")){
			return TableType.HASSUBJECT;
		}else if(dbType.equals("holdrequest")){
			return TableType.HOLDREQUEST;
		}else if(dbType.equals("bookcopy")){
			return TableType.BOOKCOPY;
		}else if(dbType.equals("fine")){
			return TableType.FINE;
		}else if(dbType.equals("borrowing")){
			return TableType.BORROWING;
		}
		return null;
	}

	@Override
	public void cleanUp() {
		
	}
	
	public static final class Command {
		
		private CommandType type;
		private TableType tableType;
		private String[] args;
		private String message;
		
		public Command(CommandType type, String msg, String... args){
			this.type = type;
			this.args = args;
			message = msg;
		}
		
		public Command(CommandType type, String msg, TableType tableType, String... args){
			this.type = type;
			this.args = args;
			this.tableType = tableType;
			message = msg;
		}
		
		public String[] getArgs(){
			return args;
		}
		
		public CommandType getType(){
			return type;
		}
		
		public TableType getTableType(){
			return tableType;
		}
		
		public String getMessage(){
			return message;
		}

	}
	
}
